#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/mman.h>
#include <string.h>
#include <stdlib.h>


//保存执行 帧缓存内存的首地址
int *plcd=NULL;

//0~9的模，宽度16
unsigned char w_digit[][58] = {
	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0xC0,0x1E,0xF0,
0x3C,0x78,0x38,0x38,0x78,0x3C,0x78,0x3C,0x70,0x1C,0x70,0x1C,0x70,0x1C,0x70,0x1C,
0x70,0x1C,0x70,0x1C,0x70,0x3C,0x78,0x3C,0x78,0x38,0x38,0x38,0x3C,0x70,0x1E,0xF0,
0x07,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x80,0x03,0x80,
0x1F,0x80,0x03,0x80,0x03,0x80,0x03,0x80,0x03,0x80,0x03,0x80,0x03,0x80,0x03,0x80,
0x03,0x80,0x03,0x80,0x03,0x80,0x03,0x80,0x03,0x80,0x03,0x80,0x03,0x80,0x03,0xC0,
0x1F,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xE0,0x1C,0x70,
0x38,0x38,0x78,0x3C,0x78,0x3C,0x78,0x3C,0x38,0x38,0x00,0x78,0x00,0x70,0x00,0xE0,
0x01,0xC0,0x03,0x80,0x07,0x00,0x0E,0x00,0x1C,0x0C,0x38,0x1C,0x70,0x3C,0x7F,0xF8,
0x7F,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xC0,0x38,0xF0,
0x38,0x78,0x78,0x78,0x38,0x78,0x00,0x78,0x00,0x70,0x00,0xE0,0x07,0xC0,0x00,0xF0,
0x00,0x78,0x00,0x38,0x00,0x3C,0x00,0x3C,0x78,0x3C,0x78,0x38,0x78,0x38,0x38,0xF0,
0x0F,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE0,0x00,0xE0,0x01,0xE0,
0x03,0xE0,0x03,0xE0,0x07,0xE0,0x0E,0xE0,0x0C,0xE0,0x1C,0xE0,0x18,0xE0,0x30,0xE0,
0x70,0xE0,0x60,0xE0,0xFF,0xFC,0x00,0xE0,0x00,0xE0,0x00,0xE0,0x00,0xE0,0x01,0xF0,
0x07,0xFC,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3F,0xF8,0x3F,0xF8,
0x38,0x00,0x38,0x00,0x38,0x00,0x38,0x00,0x30,0x00,0x37,0xE0,0x3C,0x70,0x38,0x38,
0x10,0x3C,0x00,0x3C,0x00,0x3C,0x78,0x3C,0x78,0x3C,0x78,0x38,0x38,0x78,0x38,0xF0,
0x0F,0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0xF0,0x0E,0x78,
0x1C,0x78,0x38,0x78,0x38,0x00,0x78,0x00,0x70,0x00,0x77,0xE0,0x7E,0x78,0x78,0x38,
0x78,0x3C,0x70,0x3C,0x70,0x1C,0x70,0x1C,0x78,0x3C,0x38,0x3C,0x3C,0x38,0x1E,0x70,
0x0F,0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3F,0xFC,0x3F,0xF8,
0x78,0x38,0x70,0x30,0x60,0x60,0x00,0x60,0x00,0xC0,0x01,0xC0,0x01,0xC0,0x03,0x80,
0x03,0x80,0x03,0x80,0x07,0x80,0x07,0x00,0x07,0x00,0x07,0x00,0x0F,0x00,0x0F,0x00,
0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xE0,0x3C,0x70,
0x38,0x38,0x70,0x3C,0x70,0x1C,0x70,0x1C,0x38,0x38,0x3E,0x70,0x0F,0xE0,0x1F,0xE0,
0x38,0xF0,0x70,0x78,0x70,0x3C,0x70,0x1C,0x70,0x1C,0x70,0x1C,0x70,0x38,0x3C,0x70,
0x0F,0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xC0,0x3C,0x70,
0x38,0x38,0x78,0x38,0x70,0x3C,0x70,0x3C,0x70,0x1C,0x70,0x3C,0x70,0x3C,0x78,0x7C,
0x3C,0xFC,0x1F,0xFC,0x00,0x3C,0x00,0x38,0x00,0x38,0x38,0x70,0x38,0x70,0x3D,0xE0,
0x1F,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}
};

//这个函数，如果传递x,y,color来，我就在LCD上对应的x,y坐标显示color
void LCD_Draw_Point(int x, int y, int color)
{
	if(x>=0 && x<800 && y>=0 && y<480)
	{
		*(plcd+y*800+x) = color;
	}
}
//刷屏的函数
void LCD_Brush(int color)
{
	int x, y;
	for(y=0;y<480;y++)
	for(x=0;x<800;x++)
	{
		LCD_Draw_Point(x, y, color);
	}
}

//画圆的函数:提供 x0,y0, r, color
void LCD_Draw_circle(int x0, int y0, int r, int color)
{
	int x, y;
	for(y=0;y<480;y++)
	for(x=0;x<800;x++)
	{
		if((x-x0)*(x-x0)+(y-y0)*(y-y0)<= r*r)
		{
			LCD_Draw_Point(x, y, color);
		}
	}
}
//四页草的的圆心： 400,240

//显示 图片
void LCD_Draw_picture(int x0, int y0, int width, int height, unsigned char image[])
{
	int x, y,k=0;
	int color;
	for(y=height-1;y>=0;y--)
	for(x=0;x<width;x++)
	{	//0XA5,0XBB,0X95  -> 0xA5bb95
		color = image[k]|(image[k+1]<<8)|(image[k+2]<<16);
		LCD_Draw_Point(x0+x, y0+y, color);
		k = k+3;
	}
}
//把bmp图片文件直接放到当前目录，直接打开那个bmp文件,完成显示的功能
int LCD_Draw_bmp(int x0,int y0, char *bmpfile)
{
	int fd;
	//buf[0]: 范围               0----255
	// char buf[4]范围： -----  -128----127
	unsigned char buf[4];
	int width,height,depth;
	fd = open(bmpfile, O_RDONLY);
	if(fd < 0)
	{
		printf("open failed\n");
		return -1;
	}
	//1. 定位到 图片文件的0x12，读出该图片的 宽的像素点
	lseek(fd, 0x12, SEEK_SET);
	read(fd, buf, 4);
	//小端模式存放,低字节放在低位
	width = (buf[3]<<24)|(buf[2]<<16)|(buf[1]<<8) | buf[0] ;
	printf("width = %d\n", width);

	//2. 定位到 图片文件的0x16，读出该图片的 高的像素点
	lseek(fd, 0x16, SEEK_SET);
	read(fd, buf, 4);
	//小端模式存放,低字节放在低位
    height = (buf[3]<<24)|(buf[2]<<16)|(buf[1]<<8) | buf[0] ;
	printf("height = %d\n", height);
	
	//3. 定位到 图片文件的0x1c，读出该图片的 色深
	lseek(fd, 0x1c, SEEK_SET);
	read(fd, buf, 2);
	//小端模式存放,低字节放在低位
	depth = (buf[1]<<8) | buf[0] ;
	printf("depth = %d\n", depth);

	//用同样的方式去获取 高，色深. 
	//知道了 宽，高，色深： 才可以去分配一个缓存区： 用来存放像素数组的
	unsigned char *image = malloc(width*height*depth/8);
	//从1.bmp中读出这么多个 字节 ，存放到 plcd所指向的内存空间
	lseek(fd, 0x36, SEEK_SET);
	read(fd, image, width*height*depth/8);

	//再调用上面的 显示图片的函数
    LCD_Draw_picture(x0,y0,width, height, image);
}

//在x,y 坐标显示 一个英文字符
void LCD_Draw_8x16(int x0, int y0, unsigned char p[],int color)
{
	int x,y;
	//一共是16行：循环16次，每次取一个 字节
	for(y=0;y<16;y++) 
	{
		//打点，行扫描，一行8个点
		for(x=0;x<8;x++)
		{
			if( p[y]&(1<<(7-x))) 
			{
				LCD_Draw_Point(x+x0,y+y0,color);
			}
		}
	}
}

//在x,y 坐标显示 一个中文字符
void LCD_Draw_16x16(int x0, int y0, unsigned char p[],int color)
{
	int x,y;
	//一共是16行：循环16次，每次取一个 字节
	for(y=0;y<16;y++) 
	{
		//打点，行扫描，一行前8个点
		for(x=0;x<8;x++)
		{	 
			if( p[2*y]&(1<<(7-x))) 
			{
				LCD_Draw_Point(x+x0,y+y0,color);
			}
		}
		//打点，行扫描，一行后8个点
		for(x=0;x<8;x++)
		{	 
			if( p[2*y+1]&(1<<(7-x))) 
			{
				LCD_Draw_Point(x+x0+8,y+y0,color);
			}
		}
	}
}

int init_lcd(void)
{
	int fd;
	int x, y;
	fd = open("/dev/ubuntu_lcd", O_RDWR);
	if(fd < 0)
	{
		printf("Sorry, failed to open /dev/ubuntu_lcd\n");
		return -1;
	}

	plcd = mmap(NULL,800*480*4,PROT_WRITE|PROT_READ,MAP_SHARED,fd,0);
	if(plcd == MAP_FAILED)
	{
		printf("mmap failed\n");
		return -1;
	}
	return fd;

}

void lcd_draw_rect(int x0, int y0, int w, int h, int color)
{
	int x, y;
	
	for (y = y0; y < y0+h; y++)
	{
		for (x = x0; x < x0+w; x++)
			LCD_Draw_Point(x, y, color);
	}
}

//在坐标为x0,y0的位置开始显示一张bmp图片，图片的名字为file,宽度是w，高度是h
void lcd_draw_bmp(char *file, int w, int h, int x0, int y0)
{
	//先打开bmp图片
	int fd;
	fd = open(file, O_RDWR);
	if (-1 == fd)
	{
		printf("open bmp: %s error !\n", file);
		return ;
	}
	
	char buf[w*h*3 + 54];
	//将bmp图片的像素点读取到buf中
	read(fd, buf, sizeof(buf));
	
	//将bmp图片显示在LCD上
	int color;
	int i = 0;
	int x, y;
	for (y = 0; y < h; y++)
	{
		for (x = 0; x < w; x++)
		{
			char b, g, r;
			b = buf[54+i];
			g = buf[55+i];
			r = buf[56+i];
			i += 3;
			color = r<<16 | g<<8 | b;
			LCD_Draw_Point(x+x0,h-1-y+y0,color);
		}
	}
}
void lcd_draw_word(char *ch, int len, int w, int color, int x0, int y0)
{
	int i,j;
	int x, y;
	int flag = w/8;
	//遍历整个点阵数组
	for (i = 0; i < len; i++)
	{
		for (j = 7; j >= 0; j--)
		{
			//if (ch[i] & (0x80/pow(2,7-j)))
			if ((ch[i] >> j) & 1)
			{
				x = 7-j+8*(i%flag) + x0;
				y = i/flag + y0;
				LCD_Draw_Point(x, y, color);
			}
		}
	}
}

//在坐标为x0,y0的位置开始显示数字，数字的值为value，显示的颜色为 color
void lcd_draw_digit(int value,int x0, int y0, int color)
{
	//判断是几位数
	int q,b,s,g;
	if (value / 1000)
	{
		q = value/1000;
		lcd_draw_word(w_digit[q],sizeof(w_digit[q]),16,color,x0,y0);
		//lcd_draw_num(q,32,100,100,RED);	
		b = value/100%10;
		lcd_draw_word(w_digit[b],sizeof(w_digit[b]),16,color,x0+20,y0);
		s = value/10%10;
		lcd_draw_word(w_digit[s],sizeof(w_digit[s]),16,color,x0+40,y0);
		g = value%10;
		lcd_draw_word(w_digit[g],sizeof(w_digit[g]),16,color,x0+60,y0);
	}
	else if (value / 100)
	{
		b = value/100;
		lcd_draw_word(w_digit[b],sizeof(w_digit[b]),16,color,x0+20,y0);
		s = value/10%10;
		lcd_draw_word(w_digit[s],sizeof(w_digit[s]),16,color,x0+40,y0);
		g = value%10;
		lcd_draw_word(w_digit[g],sizeof(w_digit[g]),16,color,x0+60,y0);	
	}
	else if (value / 10)
	{
		s = value/10;
		lcd_draw_word(w_digit[s],sizeof(w_digit[s]),16,color,x0+40,y0);
		g = value%10;
		lcd_draw_word(w_digit[g],sizeof(w_digit[g]),16,color,x0+60,y0);
	}
	else 
	{
		lcd_draw_word(w_digit[value],sizeof(w_digit[value]),16,color,x0+60,y0);
	}
}

